package nio;

import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;

import java.io.IOException;
import java.lang.reflect.Array;
import java.net.InetSocketAddress;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Arrays;

/**
 * @author chenyuan
 * @date 2020/11/2 15:40
 */
public class ScatteringAndGatheringTest {
	/*
	Scattering : 将数据写入到 Buffer 时，可以采用 Buffer 数组，依次写入【分散】
	Gathering : 从 Buffer 读取数据，可以采用 Buffer 数组，依次读取
	 */
	public static void main(String[] args) throws Exception {
		// 使用 ServerSocketChannel 和 InetSocketAddress 网络
		ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
		InetSocketAddress inetSocketAddress = new InetSocketAddress(6666);

		// 绑定端口到 socket，并启动
		serverSocketChannel.socket().bind(inetSocketAddress);

		// 创建 Buffer 数组
		ByteBuffer[] byteBuffers = new ByteBuffer[2];
		byteBuffers[0] = ByteBuffer.allocate(5);
		byteBuffers[1] = ByteBuffer.allocate(3);

		// 等待客户端连接（telnet）
		SocketChannel socketChannel = serverSocketChannel.accept();

		// 循环的读取数据
		while (true) {
			// 表示累计读取的字节数
			int byteRead = 0;
			// 假设从客户端最多接收 8 个字节
			while (byteRead < 8) {
				// 自动把数据分配到 byteBuffers-0、byteBuffers-1
				long read = socketChannel.read(byteBuffers);
				byteRead += read;
				// 使用流打印，查看当前 Buffer 的 Position 和 Limit
				Arrays.asList(byteBuffers).stream().
						map(byteBuffer -> "{position: " + byteBuffer.position() + ", limit: " + byteBuffer.limit() + "}")
						.forEach(System.out::println);
			}
			// 将所有的 Buffer 进行反转，为后面的其他操作做准备
			Arrays.asList(byteBuffers).forEach(Buffer::flip);

			// 将数据读出，显示到客户端
			int byteWrite = 0;
			while (byteWrite < 8) {
				long write = socketChannel.write(byteBuffers);
				byteWrite += write;
			}
			// 在控制台打印数据
			Arrays.asList(byteBuffers).forEach(buffer -> {
				System.out.print(new String(buffer.array()));
			});
			// 将所有的 Buffer 进行清空，为后面的其他操作做准备
			Arrays.asList(byteBuffers).forEach(Buffer::clear);

			// 打印处理的字节数
			System.out.println("{byteRead: " + byteRead + ", byteWrite: " + byteWrite + "}");
		}

	}
}
